
/* -*-C-*-
 ##############################################################################
 #
 # File:        trice/src/intr.c
 # RCS:         "@(#)$Revision: 1.13 $ $Date: 94/03/09 11:04:51 $"
 # Description: Routines for configuring interrupt functions in E1430 module
 # Author:      Doug Passey
 # Created:     
 # Language:    C
 # Package:     E1430
 # Status:      "@(#)$State: Exp $"
 #
 # (C) Copyright 1992, Hewlett-Packard Company, all rights reserved.
 #
 ##############################################################################
 #
 # Please add additional comments here
 #
 # Revisions:
 #
 ##############################################################################
*/

#    include <stdio.h>

#include "trice.h"
#include "err1430.h"


#ifndef lint
const char i1430_intr_fileId[] = "$Header: intr.c,v 1.13 94/03/09 11:04:51 chriss Exp $";
#endif

/*****************************************************************************
 *
 * Return register bits in <bitsPtr> for <priority>.
 * Returns 0 if OK, else returns negative error.
 *
 ****************************************************************************/
static SHORTSIZ16 i1430_get_interrupt_priority_bits(SHORTSIZ16 priority, 
							SHORTSIZ16 *bitsPtr)
{
  char buf[80];
 
  if(priority < 0 || priority > 7) {	/* incorrect priority number */
    (void)sprintf(buf, "%d", (LONGSIZ32)priority);
    return (i1430_Error(ERR1430_ILLEGAL_INTR_PRIORITY, buf, NULL));
  }

  *bitsPtr = priority;
  return (0);
}


/*****************************************************************************
 *
 * Return register bits in <bitsPtr> for <mask>.
 * Returns 0 if OK, else returns negative error.
 *
 ****************************************************************************/
static SHORTSIZ16 i1430_get_interrupt_mask_bits(SHORTSIZ16 mask, SHORTSIZ16 *bitsPtr)
{
  char buf[80];
 
  if(mask & IRQ_CONFIG_MASK_MASK) {		/* if illegal mask bits */
    (void)sprintf(buf, "0x%X", (LONGSIZ32)mask);
    return (i1430_Error(ERR1430_ILLEGAL_INTR_MASK, buf, NULL));
  }

  *bitsPtr = mask;
  return (0);
}


/*****************************************************************************
 *
 * Return interrupt register offset in <regPtr> from <intrNum>.
 * Returns 0 if OK, else returns negative error.
 *
 ****************************************************************************/
static SHORTSIZ16 i1430_get_interrupt_register(SHORTSIZ16 intrNum, SHORTSIZ16 *regPtr)
{
  char buf[80];
 
  if(intrNum != 0 && intrNum != 1) {	/* incorrect interrupt number */
    (void)sprintf(buf, "%d", (LONGSIZ32)intrNum);
    return (i1430_Error(ERR1430_ILLEGAL_INTR_NUMBER, buf, NULL));
  }

  *regPtr = (intrNum) ? E1430_IRQ_CONFIG_1_REG : E1430_IRQ_CONFIG_0_REG;
  return (0);
}


/*****************************************************************************
 *
 * Configures the first module in a group, <groupID> to pull interrupt line,
 * <priority> when the condition(s) present in <mask> happen.  <intrNum>
 * points to the interrupt generator to use.
 * 
 ****************************************************************************/
SHORTSIZ16 e1430_set_interrupt(SHORTSIZ16 groupID, SHORTSIZ16 intrNum, 
				SHORTSIZ16 priority, SHORTSIZ16 mask)
{
  SHORTSIZ16 bits, intrReg, modBits, bitsMask;
  SHORTSIZ16 error;

  error = i1430_get_interrupt_register(intrNum, &intrReg);
  if(error) return (error);

  error = i1430_get_interrupt_priority_bits(priority, &bits);
  if(error) return (error);
  modBits = bits;

  error = i1430_get_interrupt_mask_bits(mask, &bits);
  if(error) return (error);
  modBits |= bits;

  bitsMask = IRQ_CONFIG_PRIORITY_MASK & IRQ_CONFIG_MASK_MASK;

  error = i1430_update_group_module_bits(groupID, intrReg, bitsMask, modBits);
  if(error) return (error);

  return (0);
}


/*****************************************************************************
 *
 * Return the interrupt priority of interrupt number, <intrNum> from module
 * whose index in e1430_modStates arrary is <index>.
 * Returns negative error is <intrNum> not valid.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_intr_priority_index(SHORTSIZ16 index, SHORTSIZ16 intrNum)
{
  switch(intrNum) {
    case 0:
      return (e1430_modStates[index].irqConfig0 & ~IRQ_CONFIG_PRIORITY_MASK);
    case 1:
      return (e1430_modStates[index].irqConfig1 & ~IRQ_CONFIG_PRIORITY_MASK);
    default:
      return (i1430_Error(ERR1430_ILLEGAL_INTR_NUMBER, NULL, NULL));
  }
}


/*****************************************************************************
 *
 * Returns the interrupt priority of the module group, <groupID>, into
 * the variable pointed to by <priorityPtr>.  
 * Returns 0 if OK, returns ERR1430_PARAMETER_UNEQUAL if the source is
 * not the same for all modules in the group.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_get_interrupt_priority(SHORTSIZ16 groupID, SHORTSIZ16 intrNum,
						SHORTSIZ16 *priorityPtr)
{ 
  aModGroupPtr ptr;
  SHORTSIZ16 priority, first;
  char buf[80];

  if(NULL == (ptr = i1430_valid_module_group(groupID))) {
    return (ERR1430_NO_GROUP);
  }

  if(intrNum != 0 && intrNum != 1) {
    return (i1430_Error(ERR1430_ILLEGAL_INTR_NUMBER, NULL, NULL));
  }
    
  first = i1430_get_intr_priority_index(*ptr, intrNum);
  for(; *ptr != -1; ptr++) {	/* look at priority for all modules */
    priority = i1430_get_intr_priority_index(*ptr, intrNum);
    if(priority != first) {
    (void)sprintf(buf, "%d", (LONGSIZ32)groupID);
      return (i1430_Error(ERR1430_PARAMETER_UNEQUAL, "interrupt priority", buf));
    }
  }

  *priorityPtr = priority;
  return (0);
}
 

/*****************************************************************************
 *
 * Return the interrupt mask of interrupt number, <intrNum> from module
 * whose index in e1430_modStates arrary is <index>.
 * Returns negative error is <intrNum> not valid.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_intr_mask_index(SHORTSIZ16 index, SHORTSIZ16 intrNum)
{

  switch(intrNum) {
    case 0:
      return (e1430_modStates[index].irqConfig0 & ~IRQ_CONFIG_MASK_MASK);
    case 1:
      return (e1430_modStates[index].irqConfig1 & ~IRQ_CONFIG_MASK_MASK);
    default:
      return (i1430_Error(ERR1430_ILLEGAL_INTR_NUMBER, NULL, NULL));
  }
}

/*****************************************************************************
 *
 * Returns the interrupt mask of the module group, <groupID>, into
 * the variable pointed to by <maskPtr>.  
 * Returns 0 if OK, returns ERR1430_PARAMETER_UNEQUAL if the source is
 * not the same for all modules in the group.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_get_interrupt_mask(SHORTSIZ16 groupID, SHORTSIZ16 intrNum,
						SHORTSIZ16 *maskPtr)
{ 
  aModGroupPtr ptr;
  SHORTSIZ16 mask, first;
  char buf[80];

  if(NULL == (ptr = i1430_valid_module_group(groupID))) {
    return (ERR1430_NO_GROUP);
  }

  if(intrNum != 0 && intrNum != 1) {
    return (i1430_Error(ERR1430_ILLEGAL_INTR_NUMBER, NULL, NULL));
  }
    
  first = i1430_get_intr_mask_index(*ptr, intrNum);
  for(; *ptr != -1; ptr++) {	/* look at mask for all modules */
    mask = i1430_get_intr_mask_index(*ptr, intrNum);
    if(mask != first) {
    (void)sprintf(buf, "%d", (LONGSIZ32)groupID);
      return (i1430_Error(ERR1430_PARAMETER_UNEQUAL, "interrupt mask", buf));
    }
  }

  *maskPtr = mask;
  return (0);
}
 

/*****************************************************************************
 *
 * Sets the interrupt priority of interrupt number, <intrNum> to <priority>
 * Returns negative error is <intrNum> or <priority> not valid.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_set_interrupt_priority(SHORTSIZ16 groupID, SHORTSIZ16 intrNum,
							SHORTSIZ16 priority)
{
  SHORTSIZ16 bits;
  SHORTSIZ16 error;
  SHORTSIZ16 intrReg;

  error = i1430_get_interrupt_priority_bits(priority, &bits);
  if(error) return (error);

  error = i1430_get_interrupt_register(intrNum, &intrReg);
  if(error) return (error);

  return(i1430_update_group_module_bits(groupID, intrReg, 
				IRQ_CONFIG_PRIORITY_MASK, bits));
}
 

/*****************************************************************************
 *
 * Sets the interrupt mask of interrupt number, <intrNum> to <mask>
 * Returns negative error is <intrNum> or <mask> not valid.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_set_interrupt_mask(SHORTSIZ16 groupID, SHORTSIZ16 intrNum,
							SHORTSIZ16 mask)
{
  SHORTSIZ16 bits;
  SHORTSIZ16 error;
  SHORTSIZ16 intrReg;

  error = i1430_get_interrupt_mask_bits(mask, &bits);
  if(error) return (error);

  error = i1430_get_interrupt_register(intrNum, &intrReg);
  if(error) return (error);

  return(i1430_update_group_module_bits(groupID, intrReg, 
				IRQ_CONFIG_MASK_MASK, bits));
}
